
/*
 * =====================================================================================
 *       s
 *       s
 *       s
 *       y
 *       Filename:  TTSEngineMgr.cc
 *
 *    Description:
 *
 *
 *        Version:  1.0
 *        Created:  03/06/19 15:59:09
 *       Revision:  none
 *       Compiler:  gcc
 *
 *         Author:  liushuyong (), shuyong1999@163.com
 *        Company:  shuyong
 *
 * =====================================================================================
 */

#include "TTSEngineMgr.h"
#include "SessionCache.h"
#include "CommFunc.h"
//#include "tts_api.h"
#include "ttscei.h"
#include "HttpAck.h"
#include "Statistics.h"

DECLARE_string(models_folder);

static string font_name = "nvzhongyin";

using namespace idst;

//设置模型路径
//TTSEngineService TTSEngineMgr:: mgpTTSEngine = aispeech::tts::TtsService::CreateTtsService(FLAGS_models_folder.c_str());
//TTSEngineService TTSEngineMgr::mgpTTSEngine = NULL;
void* tts_engine = NULL;    //阿里

TTSEngineMgr::TTSEngineMgr() {
#ifdef Debug
    //LOG(INFO) << "New" << endl;
#endif
    mBthreadID = INVALID_BTHREAD;
    mIsFinish.store(false, std::memory_order_relaxed);
}

TTSEngineMgr::~TTSEngineMgr() {
#ifdef Debug
    //LOG(INFO) << "Del" << endl;
#endif
}

//创建一个task
void TTSEngineMgr::CreateTTSTask(TTSEngineParam* param) {
#if 0
    mspTTSEngineTask = mgpTTSEngine->CreateTtsTask(*param);

    if (mspTTSEngineTask == NULL) {
        LOG(ERROR) << "CreateTtsTask err" << endl;
    }

#endif
    tts_task = TtsCei::instance()->CreateTask(tts_engine, 24000, kTtsCeiEncodePcm);
    //LOG(INFO) << "Create Task OK" << endl;
}

/**
 * @brief
 *
 * @param modelPath
 *
 * @return
 */
bool TTSEngineMgr::loadResouce(const string& modelPath) {
#if 0

    if (mgpTTSEngine == NULL) {
        if (FLAGS_models_folder.length() == 0) {
            LOG(INFO) << "CreateTtsService default" << endl;
            mgpTTSEngine = aispeech::tts::TtsService::CreateTtsService(NULL);
        } else {
            LOG(INFO) << "CreateTtsService model=" << FLAGS_models_folder << endl;
            mgpTTSEngine = aispeech::tts::TtsService::CreateTtsService(FLAGS_models_folder.c_str());
        }

        if (!mgpTTSEngine) {
            LOG(ERROR) << "CreateTtsService err" << endl;
            return false;
        }

        return true;
    }

#endif

    if (tts_engine == NULL) {
        TtsCei::Create("/root/resources");
        tts_engine = TtsCei::instance()->CreateEngine({
            font_name}
                                                     );
        LOG(INFO) << "TTSEngine Init OK" << endl;
    }
}

/**
 * @brief 启动合成的异步任务
 */
void TTSEngineMgr::startAsyncTask(RPCContextSPtr& rpcCtx) {
    mspRPCContext = rpcCtx; //只在第一包有异步操作，设置content
    int ret = bthread_start_background(&_bthread_handle, NULL, firstPackProc, this);

    if (0 != ret) {
        abort();
    }
}

void* TTSEngineMgr::firstPackProc(void* param) {
    TTSEngineMgr* engineMgr = static_cast < TTSEngineMgr* >(param);

    if (engineMgr == NULL) {
        LOG(ERROR) << "firstPackProc faild]";
        abort();
    }

    int ret = -1;
    float progress = 0.0;
    //TASK_RESPONSE audioData;
    //TTS_ENGINE_ERROR_CODE errCode;
    int base64Len = 0;
    string base64Str = "";
    HttpParamSPtr spHttpParam = engineMgr->mspRPCContext->mspHttpParam;
    LOG(INFO) << "req:" << spHttpParam->mReqID << ", start";

    do {
        ret = bthread_start_background(&(engineMgr->mBthreadID), NULL, ttsEngineProc, (void*) engineMgr);   //生成合成线程

        if (0 != ret) {
            LOG(ERROR) << "req:" << spHttpParam->mReqID << ", ret=" << ret << "create ttsEngineProc err";
            abort();
        }

        //读第一包数据
        usleep(500000); // TODO 在阿里的引擎中，没有阻塞机制，使用强制延迟功能
        bool err = engineMgr->readCache(engineMgr->mspRPCContext, true);
    } while (0);

    return NULL;
}

/**
 * @brief从缓存中读取数据 参数是不是可以取消
 */
bool TTSEngineMgr::readCache(RPCContextSPtr rpcCtx, bool isFist) {
    HttpParamSPtr spHttpParam = rpcCtx->mspHttpParam;
    int err;
    float mProgress = 0.0;
    string base64Str = "123";
    char output_data[kTtsFetchDataMaxLen];
    int data_length = 0;
    int word_idx = 0;
    char output_word_label[kTtsTextLabelMaxLen];

    if (kTtsCeiRetOk != TtsCei::instance()->FetchData(tts_task, output_data, data_length, word_idx, output_word_label)) {
        LOG(ERROR) << "stop tts" << endl;
        mErrNo.store(ERROR_BASE64_ENCODE_FAILED, std::memory_order_relaxed);
        goto stop_tts;
    }

    LOG(INFO) << "req=" << spHttpParam->mReqID << ", seq=" << spHttpParam->mSeqID << ", readLen=" << data_length << endl;
    //当次的请求完成释放资源
    //还有数据的时候， 不结束当前任务
    err = OK;
    httpAck(rpcCtx, err, mProgress, base64Str, "");
    rpcCtx.reset();
    return true;
stop_tts:
    err = OK;
    httpAck(rpcCtx, err, mProgress, base64Str, "");

    if (!isFist) {
        spHttpParam->mSeqID *= -1;  //将seq_id置为负数，表示当前会话结束
        TtsCei::instance()->Stop(tts_task);
        TtsCei::instance()->ReleaseTask(&tts_task);
        SessionCache::getInstance()->delSession(spHttpParam->mReqID);   //删除session
        rpcCtx.reset();
    }

    return false;
}

void* TTSEngineMgr::ttsEngineProc(void* param) {
    TTSEngineMgr* engineMgr = static_cast < TTSEngineMgr* >(param);
    string txt = engineMgr->mspRPCContext->mspHttpParam->mTxt;
    LOG(INFO) << "synthetize txt:" << txt << endl;
    void* tts_task = engineMgr->tts_task;
    TtsCei::instance()->Start(tts_task, txt.c_str(), font_name.c_str(), 0.9, 1.0, kTtsCeiNus, kTtsCeiTimeLabelNone, 48);
    //LOG (INFO) << "End";
    return NULL;
}
